package consul

import (
	"fmt"
	"os"

	"gitee.com/lichenxin/grpc-consul-server/pkg/utils"
	consulApi "github.com/hashicorp/consul/api"
	"github.com/pkg/errors"
)

var consulClient *consulApi.Client

// GetClient 获取consul客户端
func GetClient() (*consulApi.Client, error) {
	if consulClient == nil {
		c := consulApi.DefaultConfig()
		if v := os.Getenv("CONSUL_URL"); v != "" {
			c.Address = v
		}
		client, err := consulApi.NewClient(c)
		if err != nil {
			return nil, errors.WithStack(err)
		}
		consulClient = client
	}
	return consulClient, nil
}

// AddServer 增加到consul
func AddServer(serverName string, port int) (string, error) {
	ip, err := utils.GetLocalIP()
	if err != nil {
		return "", errors.WithStack(err)
	}

	hostName, err := os.Hostname()
	if err != nil {
		return "", errors.WithStack(err)
	}

	client, err := GetClient()
	if err != nil {
		return "", errors.WithStack(err)
	}

	serverID := fmt.Sprintf("%s-%s-%d", serverName, hostName, utils.RandInt(1000, 9999))
	r := &consulApi.AgentServiceRegistration{
		ID:                serverID,
		Name:              serverName,
		Port:              port,
		Address:           ip,
		EnableTagOverride: false,
		Check: &consulApi.AgentServiceCheck{
			Timeout:                        "1s",
			Interval:                       "1s",
			DeregisterCriticalServiceAfter: "3s",
			GRPC:                           fmt.Sprintf("%v:%v/%v", ip, port, ""),
		},
	}

	err = client.Agent().ServiceRegister(r)
	if err != nil {
		return "", errors.WithStack(err)
	}

	return serverID, nil
}

// DelServer 删除服务
func DelServer(serverID string) error {
	client, err := GetClient()
	if err != nil {
		return errors.WithStack(err)
	}

	err = client.Agent().ServiceDeregister(serverID)
	if err != nil {
		return errors.WithStack(err)
	}

	return nil
}

// GetServer 获取服务
func GetServer(serverID string) (*consulApi.AgentService, error) {
	client, err := GetClient()
	if err != nil {
		return nil, errors.WithStack(err)
	}

	s, _, err := client.Agent().Service(serverID, nil)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	return s, nil
}

// GetHealthServers 获取有效服务列表
func GetHealthServers(serverName string) ([]*consulApi.AgentService, error) {
	client, err := GetClient()
	if err != nil {
		return nil, errors.WithStack(err)
	}

	var i uint64
	ss, _, err := client.Health().Service(serverName, "", true, &consulApi.QueryOptions{
		WaitIndex: i,
	})
	if err != nil {
		return nil, errors.WithStack(err)
	}

	rs := make([]*consulApi.AgentService, 0)
	for _, v := range ss {
		rs = append(rs, v.Service)
	}

	return rs, nil
}

// Put 设置KV值
func Put(key, value string) error {
	client, err := GetClient()
	if err != nil {
		return errors.WithStack(err)
	}

	_, err = client.KV().Put(&consulApi.KVPair{
		Key:   key,
		Value: []byte(value),
	}, nil)

	return errors.WithStack(err)
}

// Get 获取KV值
func Get(key string) (string, error) {
	client, err := GetClient()
	if err != nil {
		return "", errors.WithStack(err)
	}

	v, _, err := client.KV().Get(key, nil)
	if err != nil {
		return "", errors.WithStack(err)
	}

	return string(v.Value), nil
}
